package com.ruihu.admin.module.business.task.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruihu.admin.common.anno.MethodLog;
import com.ruihu.admin.common.constant.JudgeEnum;
import com.ruihu.admin.common.constant.ResponseCodeConst;
import com.ruihu.admin.common.domain.PageResultDTO;
import com.ruihu.admin.common.domain.ResponseDTO;
import com.ruihu.admin.constant.CommonConst;
import com.ruihu.admin.module.business.task.constant.TaskPriorityEnum;
import com.ruihu.admin.module.business.task.constant.TaskResponseCodeConst;
import com.ruihu.admin.module.business.task.constant.TaskStatusEnum;
import com.ruihu.admin.module.business.task.dao.SubTaskDao;
import com.ruihu.admin.module.business.task.dao.TaskDao;
import com.ruihu.admin.module.business.task.domain.dto.*;
import com.ruihu.admin.module.business.task.domain.entity.SubTaskEntity;
import com.ruihu.admin.module.business.task.domain.entity.TaskEntity;
import com.ruihu.admin.module.business.task.domain.vo.TaskExcelVO;
import com.ruihu.admin.module.business.task.domain.vo.TaskProcessVO;
import com.ruihu.admin.module.business.task.domain.vo.TaskVO;
import com.ruihu.admin.module.business.task.manager.TaskManager;
import com.ruihu.admin.module.support.idgenerator.IdGeneratorService;
import com.ruihu.admin.module.support.idgenerator.constant.IdGeneratorEnum;
import com.ruihu.admin.module.system.user.constant.UserResponseCodeConst;
import com.ruihu.admin.module.system.user.domain.bo.UserBO;
import com.ruihu.admin.util.BaseEnumUtil;
import com.ruihu.admin.util.PageUtil;
import com.ruihu.admin.util.RequestTokenUtil;
import org.apache.commons.collections.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * [ 任务主表 ]
 *
 * @author Tony
 * @version 1.0
 * @company 瑞虎（南京）信息技术有限公司
 * @copyright (c)  瑞虎（南京）信息技术有限公司Inc. All rights reserved.
 * @date 2022-08-26 20:42:35
 * @since JDK1.8
 */
@Service
public class TaskService {

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private SubTaskDao subTaskDao;

    @Autowired
    private TaskManager taskManager;

    /**
     * 根据id查询
     */
    public TaskEntity getById(Long id){
        return  taskDao.selectById(id);
    }

    /**
     * 分页查询
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    @MethodLog
    public ResponseDTO<PageResultDTO<TaskVO>> queryByPage(TaskQueryDTO queryDTO) {
        Page page = PageUtil.convert2QueryPage(queryDTO);
        if (StrUtil.isEmpty(queryDTO.getStatus()) && CollectionUtil.isEmpty(queryDTO.getStatusList())) {
            // 默认查询创建、运行中、暂停的任务
            List<String> statusList = new ArrayList<>();
            statusList.add(TaskStatusEnum.CREATED.getValue());
            statusList.add(TaskStatusEnum.RUNNING.getValue());
            statusList.add(TaskStatusEnum.PAUSE.getValue());
            queryDTO.setStatusList(statusList);
        }
        List<TaskDTO> taskDTOList = taskDao.queryByPage(page, queryDTO);
        List<Long> taskIds = taskDTOList.stream().map(u -> u.getId()).collect(Collectors.toList());
        Map<Long,TaskProcessVO> processMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(taskIds)){
            List<TaskProcessVO> processVOS = subTaskDao.queryTaskProcessByTaskIds(taskIds);
            processMap =  processVOS.stream().collect(Collectors.toMap(TaskProcessVO::getMainTaskId, Function.identity()));
        }
        List<TaskVO> taskVOList = new ArrayList<>(taskDTOList.size());
        Map<Long,TaskProcessVO> newProcessMap = processMap;
        taskDTOList.stream().forEach(e -> {
            TaskVO taskVO = TaskVO.convertToTaskVO(e);
            TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(e.getStatus(), TaskStatusEnum.class);
            TaskPriorityEnum taskPriorityEnum = BaseEnumUtil.getEnumByValue(e.getPriorityId(), TaskPriorityEnum.class);
            taskVO.setStatusDesc(taskStatusEnum.getDesc());
            if(Objects.nonNull(newProcessMap)&&newProcessMap.containsKey(e.getId())){
                BigDecimal progress = newProcessMap.get(e.getId()).getProcess();
                taskVO.setProgress(progress.multiply(new BigDecimal(100)));
            }
            taskVO.setPriorityDesc(taskPriorityEnum.getDesc());
            taskVOList.add(taskVO);
        });
        page.setRecords(taskVOList);
        PageResultDTO<TaskVO> pageResultDTO = PageUtil.convert2PageResult(page);
        return ResponseDTO.succData(pageResultDTO);
    }


    /**
     * 查看详情
     * @param taskId
     * @return
     */
    @MethodLog
    public ResponseDTO<TaskVO> query(Long taskId) {
        TaskEntity entity = taskDao.selectById(taskId);
        return ResponseDTO.succData(TaskVO.convertToTaskVO(entity));
    }

    /**
     * 添加
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    @MethodLog
    public ResponseDTO<String> add(TaskAddDTO addDTO) {
        int i = 0;
        int maxCount = 3;
        for (; i < maxCount; i++) {
            try {
                return this.taskManager.add(addDTO);
            } catch (DuplicateKeyException ex) {
                // ignore print 任务编号冲突后重试3次
            }

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // ignore print
            }
        }
        if (i >= 3) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ADD_FAIL);
        }
        return ResponseDTO.succ();
    }

    /**
     * 编辑
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> update(TaskUpdateDTO updateDTO) {
        if (Objects.isNull(updateDTO.getId())) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);
        }
        TaskEntity taskEntity = this.taskDao.selectById(updateDTO.getId());
        if (Objects.isNull(taskEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);

        QueryWrapper<TaskEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_name",updateDTO.getTaskName());
        TaskEntity newTaskEntity = taskDao.selectOne(queryWrapper);
        //判断任务名称是否重复
        if(null != newTaskEntity && !newTaskEntity.getId().equals(updateDTO.getId())){
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NAME_HAS_EXISTS);
        }
        if (!Objects.equals(taskEntity.getStatus(),TaskStatusEnum.CREATED.getValue())&&CompareUtil.compare(taskEntity.getPlanNum(), updateDTO.getPlanNum()) > 0) {
            return ResponseDTO.wrap(TaskResponseCodeConst.RUNNING_TASK_PLAN_NUM_MUST_GREATER_THAN_PREVIOUS);
        }

        // 检测存在的子任务数量是否多余用户设置的任务数量
        SubTaskQueryDTO queryDTO = new SubTaskQueryDTO();
        queryDTO.setMainTaskId(taskEntity.getId());
        List<SubTaskEntity> subTaskEntityList = this.subTaskDao.queryList( queryDTO);
        if (subTaskEntityList.size() > taskEntity.getPlanNum()) {
            return ResponseDTO.wrap(TaskResponseCodeConst.MUST_GREATER_THAN_SUB_TASK_AMOUNT);
        }
        this.taskManager.updateTask(updateDTO, taskEntity);
        return ResponseDTO.succ();
    }

    /**
     * 启动任务
     * @param taskId
     * @return
     */
    @MethodLog
    public ResponseDTO<String> startTask(Long taskId) {
        if (Objects.isNull(taskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        TaskEntity taskEntity = this.taskDao.selectById(taskId);
        if (Objects.isNull(taskEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);

        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(taskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.CREATED.equals(taskStatusEnum)
                && !TaskStatusEnum.PAUSE.equals(taskStatusEnum)
                && !TaskStatusEnum.HANGING.equals(taskStatusEnum)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_STATUS_NOT_MEET_REQUIRMENT);
        }
        if(Objects.equals(TaskStatusEnum.CREATED,taskStatusEnum)){
            this.taskManager.startTask(taskEntity);
        }
        //判断任务状态是挂起还是暂停
        if(Objects.equals(TaskStatusEnum.PAUSE,taskStatusEnum)||TaskStatusEnum.HANGING.equals(taskStatusEnum)){
            TaskEntity newTaskEntity = new TaskEntity();
            newTaskEntity.setId(taskId);
            newTaskEntity.setStatus(TaskStatusEnum.RUNNING.getValue());
            newTaskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
            newTaskEntity.setUpdateTime(new Date());
            newTaskEntity.setRevision(taskEntity.getRevision());
            this.taskDao.updateByIdIgnoreEmptyValue(newTaskEntity);
        }
        return ResponseDTO.succ();
    }

    /**
     * 暂停任务
     * @param taskId
     * @return
     */
    @MethodLog
    public ResponseDTO<String> pauseTask(Long taskId) {
        if (Objects.isNull(taskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        TaskEntity taskEntity = this.taskDao.selectById(taskId);
        if (Objects.isNull(taskEntity)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);
        }

        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(taskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.RUNNING.equals(taskStatusEnum)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_STATUS_NOT_MEET_REQUIRMENT);
        }

        // 检测是否存在运行中的子任务
        if (checkRunningSubTask(taskEntity)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.REJECT_PAUSE__DUE_TO_SUB_TASK_RUNNING);
        }

        taskEntity.setStatus(TaskStatusEnum.PAUSE.getValue());
        taskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        taskEntity.setUpdateTime(new Date());
        this.taskDao.updateByIdIgnoreEmptyValue(taskEntity);

        return ResponseDTO.succ();
    }

    /**
     * 删除任务
     * @param taskId
     * @return
     */
    @MethodLog
    public ResponseDTO<String> deleteTask(Long taskId) {
        if (Objects.isNull(taskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        TaskEntity taskEntity = this.taskDao.selectById(taskId);
        if (Objects.isNull(taskEntity)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);
        }

        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(taskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.PAUSE.equals(taskStatusEnum) || !TaskStatusEnum.CREATED.equals(taskStatusEnum)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_STATUS_NOT_MEET_REQUIRMENT);
        }

        // 检测是否存在运行中的子任务
        if (checkRunningSubTask(taskEntity)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.REJECT_DELETE__DUE_TO_SUB_TASK_RUNNING);
        }

        taskEntity.setIsDelete(JudgeEnum.YES.getValue().toString());
        taskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        taskEntity.setUpdateTime(new Date());
        this.taskDao.updateByIdIgnoreEmptyValue(taskEntity);

        return ResponseDTO.succ();
    }

    @NotNull
    private boolean checkRunningSubTask(TaskEntity taskEntity) {
        SubTaskQueryDTO queryDTO = new SubTaskQueryDTO();
        queryDTO.setMainTaskId(taskEntity.getId());
        queryDTO.setMainTaskId(taskEntity.getId());
        List<SubTaskEntity> subTaskEntityList = this.subTaskDao.queryList(queryDTO);
        boolean foundRunningSubTask = subTaskEntityList.stream().anyMatch(e -> e.getStatus().equals(TaskStatusEnum.RUNNING.getValue()));
        return foundRunningSubTask;
    }

    /**
     * 删除
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> deleteByIds(List<Long> idList) {
        taskDao.deleteByIdList(idList);
        return ResponseDTO.succ();
    }

    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> deleteById(Long taskId) {
        if (Objects.isNull(taskId))
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
        TaskEntity taskEntity = this.taskDao.selectById(taskId);
        if (Objects.isNull(taskEntity)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);
        }
        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(taskEntity.getStatus(), TaskStatusEnum.class);
        if (taskStatusEnum.equals(TaskStatusEnum.COMPLETE)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.FINISH_TASK_CANNOT_DELETE);
        }
        this.taskManager.deleteTask(taskEntity);

        return ResponseDTO.succ();
    }

    /**
     * 查询全部导出对象
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    public List<TaskExcelVO> queryAllExportData(TaskQueryDTO queryDTO) {
        return taskDao.queryAllExportData( queryDTO);
    }

    /**
     * 批量查询导出对象
     * @author Tony
     * @date 2022-08-26 20:42:35
     */
    public List<TaskExcelVO> queryBatchExportData(List<Long> idList) {
        return taskDao.queryBatchExportData(idList);
    }


}
